<?php
/**
 * Description of encrypt
 *
 * @author YeFng
 */
class encrypt
{
    /**
     * 可靠加解密
     * $string
     * $expiry -1解密, 密码有效秒数
     */
    static function authcode($string, $expiry = -1, $key = '', $ckey_length=3)
    {       
        $key=='' && $key = YF_f::$config['encrypt_key'];
        // 密匙a会参与加解密
        $keya = md5($key);  
        // 密匙b用于效验数据
        $keyb = substr($keya, 3, 10);
        // 密匙c用于变化生成的密文  
        $keyc = $ckey_length ? ($expiry < 0 ? substr($string, 0, $ckey_length): substr(md5(uniqid()), -$ckey_length)) : '';  
        $cryptkey = $keya.md5($keyb.$keyc);
        // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到16位用来保存$keyb(密匙b)，解密时会通过这个密匙验证数据完整性  
        // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确  
        $string = $expiry < 0 ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry>0 ? $expiry + time() : 0) . substr(md5($keyb. $string ), 10, 6) .$string;  


        $key_length = strlen($cryptkey);
        $string_length = strlen($string);  
        $result = '';  
        $box = range(0, 255);  
        $rndkey = array();  
        // 产生密匙簿  
        for($i = 0; $i <= 255; $i++)   
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);  

        // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度  
        for($j = $i = 0; $i < 256; $i++)
          {  
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;  
            $tmp = $box[$i];  
            $box[$i] = $box[$j];  
            $box[$j] = $tmp;  
          }


        // 核心加解密部分  
        for($a = $j = $i = 0; $i < $string_length; $i++)
          {  
            $a = ($a + 1) % 256;  
            $j = ($j + $box[$a]) % 256;  
            $tmp = $box[$a];  
            $box[$a] = $box[$j];  
            $box[$j] = $tmp;  
            // 从密匙簿得出密匙进行异或，再转成字符  
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));  
          }  
        if($expiry < 0)
          { 
            $string = substr($result, 16);
            $ctime = intval(substr($result, 0, 10));
            // 验证数据有效性，请看未加密明文的格式  
            if( ($ctime==0  or $ctime-time() >0) && substr($result, 10, 6)==substr(md5($keyb. $string), 10, 6) )  
                return $string;  
            else
                return null;          
          }
        else
            return $keyc.str_replace('=', '', base64_encode($result));
    }
    /**
     * 不可逆加密
     * @param type $pass
     * @param type $salt
     * @return string
     */
    static function passwd($pass, $salt='')
    {
        $type = YF_f::$config['encrypt_passType'];
		
        $CA = array('CRYPT-MD5'=>1, 'CRYPT_BLOWFISH'=>2, 'CRYPT_SHA256'=>5, 'CRYPT_SHA512'=>6);
		if ($type=='MD5')
         {
            return md5($pass);
         }
		elseif ($type=='YF')
		 {
            $salt = $salt=='' ? randomkeys(rand(1, 3), '10') : substr($salt, 41);
            $cr = sprintf("%u", crc32($pass));
            return sha1(md5($pass). substr($cr,0,-2)  .$salt) . substr($cr,-1) . $salt;
         }
        elseif (isset($CA[$type]))
         {
            if (CRYPT_SHA256!=1 or CRYPT_MD5!=1) 
            	return '';
            if ($salt=='')
                $salt = '$'. $CA[$type] . '$' . randomkeys(12, '10');
            return crypt($pass, $salt);
         }
		else
			return $pass;
    }   
    /**
     * 可逆快速加密  
     * @param string $s
     * @param string $key
     * @return string
     */
    static function q_ed($s, $key='', $time=0)
    {		
        $key = YF_f::$config['encrypt_key_Q'] . $key;
        $key = substr(md5($key), 3,10) . substr($key, 3);
        $smd5 = md5($s.$key);
        $s = ($time ?$time +time() :0) . '@' . substr($smd5, 3,3).substr($smd5 ,15,1). $s ;//  时间@校验+字符串

        $sl = strlen($s);
        $kl = strlen($key);
        $es = '';
        for($i=0; $i<$sl; $i++){
            $ei = ($i*5/3 +$sl) % $kl;
            $es .= chr( ord($s{$i}) ^ ord($key{$ei}) );
         }
        return rawurlencode(trim(base64_encode($es), '=') );
    }
    /**
     * 解密
     * @param sting $s
     * @param sting $key
     */
    static function q_de($s, $key='')
    {
        $key = YF_f::$config['encrypt_key_Q'] . $key;
        $key = substr(md5($key), 3,10) . substr($key, 3);
        $s = base64_decode(rawurldecode($s));

        $sl = strlen($s);
        $kl = strlen($key);
        $es = '';
        for ($i=0; $i<$sl; $i++){
            $ei = ($i*5/3 +$sl) % $kl;
            $es .= chr( ord($s{$i}) ^ ord($key{$ei}) );
         }

        $time = strstr($es, '@', true); 
        if ($time && $time<time())
            return null;

        $es = strstr($es, '@');
        $s = substr($es, 5);
        $smd5 = md5($s.$key);
        if (substr($es, 1,4) == substr($smd5 ,3,3) . substr($smd5 ,15,1))
            return $s;
        return null;
    }

}
